import { PriorityQueue } from "algorithm/Priorityqueue";
import { ActionBase } from "./Actions/ActionBase";
import { ActionRoute } from "./ActionRoute";
import { generateUniqueId } from "utils/utils";
import { EAbsortCode, EActionCode } from "framework/FSM/Action/ActionCode";
import { cpu_used } from "utils/decorate/decorate";


interface ICacheObject<T>
{
    id:string;
    object:T;
}
export class  PriorityQueuePool<T  >
{
    private _pool:ICacheObject<T>[]=[];

    
    public free(obj:T)
    {
        this._pool.push({
            id:generateUniqueId(),
            object: obj
        })
    }

    public  allocQueue ()
    {
        if(this._pool.length>0)
        {
            return this._pool.pop()?.object
        }
        return undefined
    }
    public size()
    {
        return this._pool.length
    }
}

/*@profile*/
export class ActionManager<T extends IActionCMD=IActionCMD>
{
    // action key 是动态变化的。所以不存在的key需要回收。而且优先队列，可以做一个队列池，用于复用
    private ActionSequence:Map<string,PriorityQueue<T>>= new Map<string,PriorityQueue<T>>();
    private sequencePool:PriorityQueuePool<PriorityQueue<T>>;
    private executeQueue:string[]=[];
    private activeQueue:Set<string> = new Set<string>;
    constructor()
    {
        this.sequencePool = new PriorityQueuePool<PriorityQueue<T>>()
    }
    /**
     * push 新Action ,push的时候已经分配了 ActionSequence
     * @param key 
     * @param actions 
     */
   
    public pushAction(key:string,actions:T[])
    {
        // actions.forEach(e=>this.execute(e))
        // return 
        if(this.ActionSequence.has(key))
        {
            this.ActionSequence.get(key)?.clear();
            this.ActionSequence.get(key)?.pushMany(actions);
        }
        else
        {
            const obj = this.sequencePool.allocQueue();
            if(obj)
            {
                obj.pushMany(actions);
                this.ActionSequence.set(key,obj)
                
                
            }
            else
            {
                const compare = (a:T,b:T)=>{
                    return a.priority > b.priority;
                }
                this.ActionSequence.set(key,new PriorityQueue<T>({
                    comparator:compare,
                    initialElements:actions
                }))
            
            }
        }
        this.executeQueue.push(key);
    }

    public executeActions()
    {
       //  global.Log.Info(`执行动作 长度 ${this.executeQueue.length} `);
        const freeRecord:string[] = []
        this.executeQueue.forEach((k)=>
        {
            const v =  this.ActionSequence.get(k) as PriorityQueue<T>;
            if(v.size() ==0)
            {
                freeRecord.push(k);
            }
            else 
            {
                while(v.size()>0)
                {
                    const action = v.pop() as T ;
                    this.execute(action);
                }
            }
        })
        for(const e of freeRecord)
        {
            this.sequencePool.free(this.ActionSequence.get(e) as any);
            this.ActionSequence.delete(e);
            
        }
        this.executeQueue.splice(0,this.executeQueue.length);
    }
    /**
     * 当发生错误中断后。后面的Action都可以不用执行了
     * @param action 
     */
    @cpu_used((action:any)=>{
        return `${action.arg.entity.GUID()}-${action.key}`
    },
    (action:any,cpu:number)=>
    {
        return action.arg.entity.entityType()=="Creep" && cpu>1
    },
    (text,action)=>
    {
        console.log(text,action.arg.entity.memory.Debug['log'])
    }
    )
    private execute(action:T)
    {
        
        
        const code =  ActionRoute.Execute(action);
        if(code == EActionCode.FAILED && action.onError)
        {
            action.onError();
            (action as any).onError=undefined
        }
        return code
    }

    /**
     * 
     * @param key 
     * @returns 0 继续 1.队列空了 2.队列不存在
     */
    public executeAction(key:string)
    {
        
       //  global.Log.Info(`执行动作 长度 ${this.executeQueue.length} `);
        const v =  this.ActionSequence.get(key) as PriorityQueue<T>;
        if(v)
        {
            this.activeQueue.add(key);
            // 有Action队列
            for(let i =0;i<v.size();i++)
            {
                const action = v.getAt(i) as T ;
                const code = this.execute(action);
                if(code !== EActionCode.RUNNING)
                {
                    // 则移除
                    //action.arg.entity.log(`warn`,`Action 完成 ${action.key}`)
                    if(action.absort == EAbsortCode.BOTH)
                    {
                        v.deleteAt(i);
                       
                        while (i<v.size())
                        {
                            const action = v.getAt(i) as T ;
                            this.execute(action);
                            v.deleteAt(i);
                           
                        }
                    }
                    else if(action.absort == EAbsortCode.LOW)
                    {
                        v.deleteAt(i);
                        i--;
                    }
                    else 
                    {
                        v.deleteAt(i);
                        i--;
                    }
                    
                }
            }
            if(v.size() == 0)
            {
                return 1;
            }
            else 
            {
                return 0;
            }
        }
        else 
        {
            // 没有Action队列
            global.Log.Error(`没有动作队列 ${key}`)
            // throw new Error(`未初始化的动作队列 ${key}`)
            return 2
        }
        
    }

    public clearAction(key:string)
    {
        //global.Log.Info('清理ACtion'+key)
        const v =  this.ActionSequence.get(key) as PriorityQueue<T>;
        if(v)
        {
            //global.Log.Info('清理ACtion'+key,'成功')
            v.clear();
        }
    }
    /**
     * 开始记录激活的 执行对象
     */
    public actionStart()
    {
        this.activeQueue.clear();
    }


    /**
     * 结束时 清理过期的队列
     */
    public actionEnd()
    {
        const freeRecord:string[] = []
        this.ActionSequence.forEach((v,k)=>
        {
            if(!this.activeQueue.has(k))
            {
                freeRecord.push(k);
            }
        })
        global.Log.Warning(`当前队列 ${this.ActionSequence.size}`,`待释放队列 ${freeRecord.length}`,`队列池 ${this.sequencePool.size()}`)
        for(const e of freeRecord)
        {
            this.ActionSequence.get(e)?.clear();
            this.sequencePool.free(this.ActionSequence.get(e) as any);
            this.ActionSequence.delete(e);
            
        }
        
    }
}